package com.sgj.utils;

import com.alibaba.fastjson.JSONObject;
import com.alipay.api.AlipayApiException;
import com.alipay.api.AlipayClient;
import com.alipay.api.DefaultAlipayClient;
import com.alipay.api.request.AlipayTradePrecreateRequest;
import com.alipay.api.response.AlipayTradePrecreateResponse;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.node.ObjectNode;
import com.wechat.pay.contrib.apache.httpclient.WechatPayHttpClientBuilder;
import com.wechat.pay.contrib.apache.httpclient.auth.AutoUpdateCertificatesVerifier;
import com.wechat.pay.contrib.apache.httpclient.auth.PrivateKeySigner;
import com.wechat.pay.contrib.apache.httpclient.auth.WechatPay2Credentials;
import com.wechat.pay.contrib.apache.httpclient.auth.WechatPay2Validator;
import com.wechat.pay.contrib.apache.httpclient.util.PemUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.util.EntityUtils;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

import javax.servlet.http.HttpServletResponse;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.security.PrivateKey;

/**
 * 支付集成
 * @Author: Guoji Shen
 * @Date: 2021/11/29 8:58
 */
@Slf4j
@Component
public class PayUtil {

    // 微信appid
    private static String WX_APPID;
    // 微信api3密钥
    private static String WX_APIV3_PRIVATEKEY;
    // 微信证书密钥
    private static String WX_PRIVATEKEY;
    // 微信证书序列号
    private static String WX_MERCHANTSERIALNUMBER;
    // 微信商户号
    private static String WX_MER_ID;
    // 微信回调地址
    private static String WX_NOTIFY_URL;
    // 支付宝appid
    private static String ALI_APPID;
    // 支付宝公钥
    private static String ALI_ALIPAYPUBLICKEY;
    // 支付宝密钥
    private static String ALI_PRIVATEKEY;
    // 支付宝回调地址
    private static String ALI_NOTIFY_URL;

    // 读取对应配置文件并给静态参数赋值
    @Value("${wxpay.appid}")
    public void setWxAppid(String appId) {
        WX_APPID = appId;
    }
    @Value("${wxpay.apiv3PrivateKey}")
    public void setWxApiv3Privatekey(String apiv3Privatekey) {
        WX_APIV3_PRIVATEKEY = apiv3Privatekey;
    }
    @Value("${wxpay.privateKey}")
    public void setWxPrivatekey(String privatekey) {
        WX_PRIVATEKEY = privatekey;
    }
    @Value("${wxpay.merchantSerialNumber}")
    public void setWxMerchantserialnumber(String merchantserialnumber) {
        WX_MERCHANTSERIALNUMBER = merchantserialnumber;
    }
    @Value("${wxpay.mer_id}")
    public void setWxMerId(String merId) {
        WX_MER_ID = merId;
    }
    @Value("${wxpay.notifyUrl}")
    public void setWxNotifyUrl(String notifyUrl) {
        WX_NOTIFY_URL = notifyUrl;
    }
    @Value("${alipay.appid}")
    public void setAliAppid(String appId) {
        ALI_APPID = appId;
    }
    @Value("${alipay.alipayPublicKey}")
    public void setAliAlipaypublickey(String payPublicKey) {
        ALI_ALIPAYPUBLICKEY = payPublicKey;
    }
    @Value("${alipay.privateKey}")
    public void setAliPrivatekey(String privatekey) {
        ALI_PRIVATEKEY = privatekey;
    }
    @Value("${alipay.notifyUrl}")
    public void setAliNotifyUrl(String notifyUrl) {
        ALI_NOTIFY_URL = notifyUrl;
    }


    /**
     * 支付宝扫码支付(native)
     * @param amount        金额(单位为元)
     * @param orderName     订单名称
     * @param orderNo       订单号
     * @param response
     * @return
     * @throws AlipayApiException
     */
    public static void ALIPay(Double amount, String orderName, String orderNo, HttpServletResponse response) throws AlipayApiException {
        AlipayClient alipayClient = new DefaultAlipayClient("https://openapi.alipay.com/gateway.do", ALI_APPID,
                ALI_PRIVATEKEY, "json", "UTF-8", ALI_ALIPAYPUBLICKEY, "RSA2");
        // 创建 API 对应的 request 类
        AlipayTradePrecreateRequest request = new AlipayTradePrecreateRequest();
        // 传入指定参数，具体根据官方文档
        JSONObject bizContent = new JSONObject();
        bizContent.put("out_trade_no", orderNo);
        bizContent.put("total_amount", amount);
        bizContent.put("subject", orderName);

        request.setBizContent(bizContent.toString());
        request.setNotifyUrl(ALI_NOTIFY_URL);
        AlipayTradePrecreateResponse alipayTradePrecreateResponse = alipayClient.execute(request);
        log.info("[PayUtil][ALIPay] 支付宝支付请求发送成功:{}", JSONObject.toJSONString(alipayTradePrecreateResponse.getBody()));

        // 解析回调 url
        String qcCode = JSONObject.parseObject(JSONObject.parseObject(alipayTradePrecreateResponse.getBody())
                .getString("alipay_trade_precreate_response")).getString("qr_code");

        // 生成二维码
        createQrCodeByUrl(qcCode, response);
    }

    /**
     * 微信扫码支付(native)
     * @param amount        金额(单位为分)
     * @param orderName     订单名称
     * @param orderNo       订单号
     * @param response
     * @return
     * @throws IOException
     */
    public static void WXPay(Integer amount, String orderName, String orderNo, HttpServletResponse response) throws IOException {
        // 通过字符串方式转换证书私钥(此处也可以用文件指定方式处理)
        PrivateKey merchantPrivateKey = PemUtil.loadPrivateKey(new ByteArrayInputStream(WX_PRIVATEKEY.getBytes("utf-8")));

        // 自动更新并获取证书
        AutoUpdateCertificatesVerifier verifier = new AutoUpdateCertificatesVerifier(
                new WechatPay2Credentials(WX_MER_ID, new PrivateKeySigner(WX_MERCHANTSERIALNUMBER, merchantPrivateKey)),
                WX_APIV3_PRIVATEKEY.getBytes("utf-8"));

        WechatPayHttpClientBuilder builder = WechatPayHttpClientBuilder.create()
                .withMerchant(WX_MER_ID, WX_MERCHANTSERIALNUMBER, merchantPrivateKey)
                .withValidator(new WechatPay2Validator(verifier));

        // 通过 WechatPayHttpClientBuilder 构造的 HttpClient，会自动的处理签名和验签
        CloseableHttpClient httpClient= builder.build();
        HttpPost httpPost = new HttpPost("https://api.mch.weixin.qq.com/v3/pay/transactions/native");
        httpPost.addHeader("Accept", "application/json");
        httpPost.addHeader("Content-type","application/json; charset=utf-8");

        ByteArrayOutputStream bos = new ByteArrayOutputStream();
        ObjectMapper objectMapper = new ObjectMapper();

        ObjectNode rootNode = objectMapper.createObjectNode();

        // 传入指定参数，具体根据官方文档
        rootNode.put("mchid", WX_MER_ID)
                .put("appid", WX_APPID)
                .put("description", orderName)
                .put("notify_url", WX_NOTIFY_URL)
                .put("out_trade_no", orderNo);
        rootNode.putObject("amount")
                .put("total", amount)
                .put("currency", "CNY");

        objectMapper.writeValue(bos, rootNode);

        httpPost.setEntity(new StringEntity(bos.toString("UTF-8"), "UTF-8"));
        // 发送请求
        CloseableHttpResponse closeableHttpResponse = httpClient.execute(httpPost);

        String bodyAsString = EntityUtils.toString(closeableHttpResponse.getEntity());
        log.info("[PayUtil][WXPay] 微信支付请求发送成功:{}", JSONObject.toJSONString(bodyAsString));

        // 解析回调 url
        String codeUrl = JSONObject.parseObject(bodyAsString).getString("code_url");

        // 生成二维码
        createQrCodeByUrl(codeUrl, response);
    }

    /**
     * 生成二维码
     * @param codeUrl
     * @param response
     */
    public static void createQrCodeByUrl(String codeUrl, HttpServletResponse response) {
        try{
            OutputStream os = response.getOutputStream();
            QrCodeUtil.encode(codeUrl, null, os, true);
        }catch (Exception e){
            e.printStackTrace();
        }
    }
}